package com.xxc.exam.controller

import com.xxc.batis.qo.PageQO
import com.xxc.common.const.NOW
import com.xxc.common.exceptions.DataConflictException
import com.xxc.common.exceptions.ParameterInvalidException
import com.xxc.common.util.json.gson.GsonUtil
import com.xxc.exam.constant.QuesConst
import com.xxc.exam.entity.dto.AnswerDto
import com.xxc.exam.entity.dto.ContestDto
import com.xxc.exam.entity.pojo.Contest
import com.xxc.exam.entity.pojo.Manager
import com.xxc.exam.entity.pojo.Question
import com.xxc.exam.entity.vo.ContestQuesVO
import com.xxc.exam.entity.vo.ContestVO
import com.xxc.exam.entity.vo.GetContextListVO
import com.xxc.exam.service.ContestService
import com.xxc.exam.service.QuestionService
import com.xxc.exam.service.SelectionQuesService
import com.xxc.response.anotation.ResponseResult
import jdk.nashorn.internal.objects.NativeArray.forEach
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.*
import org.springframework.web.context.request.WebRequest
import java.math.BigInteger
import java.sql.Timestamp

@RestController
@ResponseResult
class ContestController {


    @Autowired
    lateinit var contestService: ContestService

    @Autowired
    lateinit var questionService: QuestionService

    @Autowired
    lateinit var selectionQuesService: SelectionQuesService

    @PostMapping("/contest")
    fun createContest(@RequestBody contest:ContestDto,@SessionAttribute auth: Manager) {
        contestService.addContest(contest,auth.id!!)
    }

    @GetMapping("/contest/{id}")
    fun startContest(@PathVariable id:BigInteger,request:WebRequest):ContestVO {
        val key = "contest$id"
        val contestAttr = request.getAttribute(key, WebRequest.SCOPE_SESSION)
        if(contestAttr != null)
        {
            return contestAttr as ContestVO
        }
        val contest = contestService.getContest(id)
        val contestQues = questionService.getContestQues(id)
        request.setAttribute("${key}ques-grouped",contestQues.groupBy {
            it.selectionId
        },WebRequest.SCOPE_SESSION)
        val start = Timestamp.from(NOW().toInstant())
        contest.startTime = start
        // 将当前时间和时长加入
        request.setAttribute(key,contest ,WebRequest.SCOPE_SESSION)
        //将题目放入session
        request.setAttribute("${key}ques",contestQues ,WebRequest.SCOPE_SESSION)
        return contest
    }

    @GetMapping("/contest/{id}/{quesIndex}")
    fun getQues(@PathVariable id:BigInteger,@PathVariable quesIndex:Int,request: WebRequest):List<ContestQuesVO>
    {
        val list = request.getAttribute("contest${id}ques",WebRequest.SCOPE_SESSION) as List<ContestQuesVO>? ?: throw DataConflictException("当前考试不存在")
        val group = request.getAttribute("contest${id}ques-grouped",WebRequest.SCOPE_SESSION) as Map<BigInteger,List<ContestQuesVO>>
        val ques = group[list[quesIndex-1].selectionId]!!
        val index = ques.indexOfFirst {
            it.index == quesIndex
        }
        val start = 10*(index/10)
        if (start > ques.size)
            throw ParameterInvalidException("index out of bounds")
        var end = start + 10
        if(end > ques.size)
            end = ques.size
        return ques.subList(start,end)
    }

    @PostMapping("/contest/{id}")
    fun endContest (@PathVariable id:BigInteger,request: WebRequest,@RequestBody answerList:List<String>):Int {
        val key = "contest$id"
        val list = request.getAttribute("contest${id}ques",WebRequest.SCOPE_SESSION) as List<ContestQuesVO>? ?: throw DataConflictException("当前考试不存在")
        val scoreMap = mutableMapOf<BigInteger,Int>()
        val mapIndexed = answerList.mapIndexed { index, item ->
            //将List<String>映射为List<AnswerDto>
            AnswerDto(index, item)
        };
        val filter = mapIndexed.filter { it.answer != null && !it.answer!!.isBlank() && it.answer != "null" }
        filter.forEach { //遍历将正确的题目数添加到Map
            val ques = list.findLast {cq->
                cq.index === it.index
            }!!
            val options = ques.options!!.split("|").map { answer -> answer.toCharArray()[0] }
            when(ques.type) {
                QuesConst.Type.SINGLE_SELECT -> {
                    //如果考生答案的位置和当前答案所在的位置相同，则是对的，相应的大题加一道正确题目
                    if (it.answer!!.toInt() == options.indexOf(ques.answer!!.toCharArray()[0])) {
                        val originCount = scoreMap[ques.selectionId!!] ?:0
                        scoreMap[ques.selectionId!!] = originCount + 1
                    }
                }
                QuesConst.Type.MULTI_SELECT -> {
                    // 考生的回答数组
                    val customAnswers = it.answer?.substring(1 , it.answer!!.length-1)!!.split(',')
                            .map {str-> str.toInt() }.toMutableList()
                    //让正确答案的每一项与选项比较获取正确答案索引数组
                    for (value in ques.answer!!.toCharArray()) {
                        val indexOf = customAnswers.indexOf(
                                options.indexOf(value)// 获取答案中的一个的位置
                        ) // 获取答案在考生答案的位置
                        if(indexOf == -1)
                        {
                            break
                        }
                        // 将每一项正确答案从考生的答案移除
                        customAnswers.removeAt(indexOf)
                    }
                    // 如果考生的答案变成空则回答正确加一题得分
                    if (customAnswers.isEmpty())
                    {
                        val originCount = scoreMap[ques.selectionId!!] ?:0
                        scoreMap[ques.selectionId!!] = originCount + 1
                    }
                }
            }
        }
        // 获取selections的perScore
        val perScoreMap = selectionQuesService.getSelectionsPerScore(scoreMap.keys.toList())
        // 获取总分
        var sumScore = 0
        scoreMap.forEach { (selectionId, count) ->
            sumScore += perScoreMap[selectionId]?.times(count) ?: 0
        }
        request.removeAttribute(key,WebRequest.SCOPE_SESSION)
        request.removeAttribute("${key}ques-grouped",WebRequest.SCOPE_SESSION)
        request.removeAttribute("${key}ques",WebRequest.SCOPE_SESSION)
        return sumScore
    }

    /**
     * 获取当前正在考的考试
     */
    @GetMapping("/contests")
    fun getCurrentContests(@SessionAttribute auth:Manager,@RequestParam(required = false) count:Int): List<GetContextListVO> {
        val contestList = contestService.getContestList(auth.id!!, PageQO<Contest>(curPage = 0, pageSize = count))
        contestList.forEach {
            it.type = 1
        }
        return contestList
    }

}